package hng.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import hng.component.RedisComponent;
import hng.constants.Constants;
import hng.dto.RegisterDTO;
import hng.dto.ResetPasswordDTO;
import hng.dto.UserDTO;
import hng.enums.UserRoleEnum;
import hng.enums.UserStatusEnum;
import hng.exception.BizException;
import hng.interceptor.LoginInterceptor;
import hng.mapper.StoreMapper;
import hng.model.LoginUser;
import hng.model.StoreDO;
import hng.model.UserDO;
import hng.mapper.UserMapper;
import hng.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import hng.util.CheckUtil;
import hng.util.CommonUtil;
import hng.util.JWTUtil;
import hng.util.SmsUtil;
import hng.vo.LoginVO;
import hng.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

/**
 * @author 告白
 * @since 2024-06-27
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService {

    @Autowired(required = false)
    private UserMapper userMapper;

    @Autowired(required = false)
    private RedisComponent redisComponent;

    @Autowired(required = false)
    private StoreMapper storeMapper;

    /**
     * 发送短信验证码
     */
    @Override
    public void sendPhoneCode(String phone) {
        boolean f = CheckUtil.isPhone(phone);
        if (!f) {
            throw new BizException("手机号码格式不正确");
        }

        if (!checkUniquePhone(phone)) {
            throw new BizException("手机号码已被注册");
        }

        String code = CommonUtil.getRandomCode(6);
        String res = SmsUtil.send(phone, code);
        if (!"0".equals(res)) {
            throw new BizException("验证码发送失败");
        }

        // 验证码放redis
        String key = String.format(Constants.REDIS_KEY_PHONE_CODE, phone);
        redisComponent.savePhoneCode(key, code);
    }

    /**
     * 注册
     */
    @Override
    public void register(RegisterDTO registerDTO) {
        // 判断手机号是否已被注册
        if (!checkUniquePhone(registerDTO.getPhone())) {
            throw new BizException("手机号码已被注册");
        }

        // 判断验证码是否正确
        String key = String.format(Constants.REDIS_KEY_PHONE_CODE, registerDTO.getPhone());
        String code = (String) redisComponent.get(key);
        if (!registerDTO.getCode().equals(code)) {
            throw new BizException("短信验证码错误");
        }

        // 开始注册
        UserDO userDO = new UserDO();
        userDO.setPhone(registerDTO.getPhone());
        userDO.setSex("保密");
        userDO.setUsername("惠农" + CommonUtil.getStringRandom(4));
        userDO.setSecret("$1$" + CommonUtil.getStringRandom(8));
        userDO.setPassword(Md5Crypt.md5Crypt(registerDTO.getPassword().getBytes(), userDO.getSecret()));
        userMapper.insert(userDO);
    }

    /**
     * 修改个人信息
     */
    @Override
    public UserVO updateInfo(UserDTO userDTO) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        UserDO userDO = new UserDO();
        BeanUtils.copyProperties(userDTO, userDO);
        userDO.setId(loginUser.getId());
        userMapper.updateById(userDO);

        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userDO, userVO);
        return userVO;
    }

    /**
     * 登录
     */
    @Override
    public LoginVO login(RegisterDTO registerDTO) {
        // 条件构造器
        LambdaQueryWrapper<UserDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 如果是手机号
        if (CheckUtil.isPhone(registerDTO.getPhone())) {
            lambdaQueryWrapper.eq(UserDO::getPhone, registerDTO.getPhone());
        } else { // 否则是用户名
            lambdaQueryWrapper.eq(UserDO::getUsername, registerDTO.getPhone());
        }
        UserDO userDO = userMapper.selectOne(lambdaQueryWrapper);

        if (userDO == null) {
            throw new BizException("用户不存在");
        }

        if (!Md5Crypt.md5Crypt(registerDTO.getPassword().getBytes(), userDO.getSecret()).equals(userDO.getPassword())) {
            throw new BizException("手机号或密码错误");
        }

        if (UserStatusEnum.DISABLED.getCode().equals(userDO.getStatus())) {
            throw new BizException("用户已被禁用");
        }

        // 卖家
        StoreDO storeDO = null;
        Integer storeId = 0;
        if (userDO.getRole().equals(UserRoleEnum.STORE.getCode())) {
            storeDO = storeMapper.selectOne(new LambdaQueryWrapper<StoreDO>().eq(StoreDO::getUserId, userDO.getId()));
        }

        // 登录成功
        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(userDO, loginUser);
        // 卖家账号 设置店铺id
        if (storeDO != null) {
            storeId = storeDO.getId();
        }
        loginUser.setStoreId(storeId);
        // 生成token
        String token = JWTUtil.getJsonWebToken(loginUser);
        String key = String.format(Constants.REDIS_KEY_TOKEN, userDO.getId());
        // token放redis
        redisComponent.setex(key, token, Constants.REDIS_KEY_EXPRIRES_DAY);

        // 返回结果
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userDO, userVO);
        LoginVO loginVO = new LoginVO();
        loginVO.setToken(token);
        loginVO.setUserInfo(userVO);
        log.info("loginUser： {}", loginUser);

        return loginVO;
    }

    /**
     * 获取用户信息
     */
    @Override
    public UserVO info() {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        UserDO userDO = userMapper.selectById(loginUser.getId());
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userDO, userVO);
        return userVO;
    }

    /**
     * 修改密码
     */
    @Override
    public void updatePassword(ResetPasswordDTO pwdDTO) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        if (!pwdDTO.getNewPwd().equals(pwdDTO.getResetPwd())) {
            throw new BizException("2次输入的密码不一致！");
        }

        UserDO userDO = userMapper.selectById(loginUser.getId());
        if (!Md5Crypt.md5Crypt(pwdDTO.getOriginPwd().getBytes(), userDO.getSecret()).equals(userDO.getPassword())) {
            throw new BizException("原密码输入错误！");
        }

        // 重置密码
        userDO.setPassword(Md5Crypt.md5Crypt(pwdDTO.getNewPwd().getBytes(), userDO.getSecret()));
        userMapper.updateById(userDO);
    }

    /**
     * 检查手机号是否唯一
     */
    private boolean checkUniquePhone(String phone) {
        Integer row = userMapper.selectCount(new LambdaQueryWrapper<UserDO>().eq(UserDO::getPhone, phone));
        return row == 0 ? true : false;
    }
}
